package com.fowo.api.syncAmazon.core.sync;

import cn.hutool.core.io.FileUtil;
import com.amazon.spapi.api.CatalogApi;
import com.amazon.spapi.client.ApiException;
import com.amazon.spapi.model.catalogitems.*;
import com.amazon.spapi.model.orders.OrderItem;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.fowo.api.entity.ListingFather;
import com.fowo.api.entity.Product;
import com.fowo.api.entity.ShopInfo;
import com.fowo.api.service.impl.ListingFatherServiceImpl;
import com.fowo.api.service.impl.ProductServiceImpl;
import com.fowo.api.syncAmazon.core.AbstractAmazonSyncData;
import com.fowo.api.syncAmazon.entity.ApiDefine;
import com.fowo.api.syncAmazon.entity.ApiRequestLog;
import com.fowo.api.syncAmazon.entity.TmpAmazonCatalogitems;
import com.fowo.api.syncAmazon.service.impl.TmpAmazonCatalogitemsServiceImpl;
import com.fowo.api.sys.entity.SysFile;
import com.fowo.api.sys.service.FileService;
import com.google.common.collect.Lists;
import com.google.common.util.concurrent.RateLimiter;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.compress.utils.IOUtils;
import org.springframework.mock.web.MockMultipartFile;
import org.springframework.stereotype.Component;
import org.springframework.util.ObjectUtils;
import org.springframework.web.multipart.MultipartFile;

import javax.annotation.Resource;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @fileName: CatalogItemSync
 * @Description: 商品目录同步
 * @Author: yyf
 * @Date: 2024/3/4 0004 15:59
 */
@Slf4j
@Component
public class CatalogItemSync extends AbstractAmazonSyncData {
    @Resource
    private ListingFatherServiceImpl listingFatherService;
    @Resource
    private TmpAmazonCatalogitemsServiceImpl tmpAmazonCatalogitemsService;
    @Resource
    private FileService fileService;
    @Resource
    private ProductServiceImpl productService;
    private RateLimiter rateLimiter = RateLimiter.create(1.5);
    private List<ListingFather> listingFather;
    List<ListingFather> updateImageList;
    private ApiDefine apiDefine = ApiDefine.builder()
            .apiCode("catalog_items")
            .initdate(1)
            .timeInterval(1)
            .timeIntervalType("day").build();

    @Override
    protected ApiDefine setApiDefine() {
        return apiDefine;
    }

    @Override
    protected void requestData() throws ApiException, InterruptedException {
        // 获取卖家账号信息
        String platform = "Amazon";
        this.getAuthority(platform);
        // 查询该账号下所有店铺
        LambdaQueryWrapper<ShopInfo> shopInfosWrapper = new LambdaQueryWrapper<>();
        shopInfosWrapper.eq(ShopInfo::getPlatform,"Amazon")
                .eq(ShopInfo::getSellerAuthStatus,"SQ01");
        List<ShopInfo> shopInfoList = shopInfoServiceImpl.list(shopInfosWrapper);
        List<Long> shopIds = shopInfoList.stream().map(ShopInfo::getId).collect(Collectors.toList());

        // 查询listing_father.asin
        LambdaQueryWrapper<ListingFather> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(ListingFather::getShop,shopIds).eq(ListingFather::getDelFlag,0)
                .eq(ListingFather::getStatus,1);
        listingFather = listingFatherService.list(wrapper);

        // 按asin和shop去重-->获取不重复的asin
        Map<Long,List<String>> shopAndAsin = new HashMap<>(listingFather.size());
        Map<Long, List<ListingFather>> listingByShop = listingFather.stream().collect(Collectors.groupingBy(ListingFather::getShop));
        for (Long shopId : listingByShop.keySet()) {
            List<ListingFather> listingFathers = listingByShop.get(shopId);
            List<String> asinList = listingFathers.stream().map(ListingFather::getAsin)
                    .distinct().collect(Collectors.toList());
            shopAndAsin.put(shopId,asinList);
        }

        logger.info("清空临时表");
        tmpAmazonCatalogitemsService.getBaseMapper().cleanAll();
        updateImageList = new ArrayList<>(listingFather.size());

        logger.info("查询产品表并冗余品牌、分类、品名、sku且更新");
        List<Long> productId = listingFather.stream().map(ListingFather::getPairProduct).distinct().collect(Collectors.toList());
        List<Product> productList = new ArrayList<>(productId.size());
        for (List<Long> list : Lists.partition(productId, 500)) {
            List<Product> products = productService.listByIds(list);
            productList.addAll(products);
        }

        List<ListingFather> updateByProductList = new ArrayList<>(productList.size());
        for (Product product : productList) {
            List<ListingFather> collect = listingFather.stream().filter(r -> r.getPairProduct() != null && r.getPairProduct().equals(product.getId()))
                    .collect(Collectors.toList());
            collect.forEach(r -> {
                r.setClassify(product.getClassify());
                r.setBrand(product.getBrand());
                r.setProductName(product.getName());
                r.setSku(product.getSku());
            });
            updateByProductList.addAll(collect);
        }
        logger.info("来自产品冗余字段的listing更新数量："+updateByProductList.size());
        listingFatherService.updateBatchById(updateByProductList);

        for (Long shopId : shopAndAsin.keySet()) {
            ShopInfo shopInfo = shopInfoList.stream().filter(r -> r.getId().equals(shopId)).findFirst().get();
            if(shopInfo == null){
                continue;
            }
            logger.info("正在获取店铺："+shopInfo.getId()+" 的商品目录信息");
            CatalogApi catalogApi = amazonUtil.getCatalogApi(entityAuthority, shopInfo);

            List<String> marketplaceIds = new ArrayList<>();
            marketplaceIds.add(shopInfo.getMarketplaceId());
            List<String> includedData = new ArrayList<>();
            //查询参数
//                includedData.add("attributes");
//                includedData.add("dimensions");
            includedData.add("identifiers");
            includedData.add("images");
            includedData.add("productTypes");
            includedData.add("relationships");
            includedData.add("salesRanks");
            includedData.add("summaries");

            List<Item> catalogList = new ArrayList<>();
            List<String> asinList = shopAndAsin.get(shopId);
            int size = asinList.size();
            for (String asin : asinList) {
                int i = 3;
                boolean isContinue = true;
                while (isContinue){
                    rateLimiter.acquire();
                    Item tmpItem = null;

                    try {
                        logger.info("正在获取的asin："+asin+"---还剩："+ size-- +"----");
                        tmpItem = catalogApi.getCatalogItem(asin, marketplaceIds, includedData, null);
                    }catch (ApiException e){
                        if (e.getCode() == 429){
                            Thread.sleep(60000);
                            tmpItem = catalogApi.getCatalogItem(asin, marketplaceIds, includedData, null);
                        }else if(e.getMessage().contains("timeout")){
                            logger.info("出现超时异常，正在重试！");
                            Thread.sleep(10000);
                            isContinue = true;
                            i--;
                            if(i == 0){
                                throw new RuntimeException(e);
                            }
                            continue;
                        } else{
                            throw new RuntimeException(e.getResponseBody());
                        }
                    }
                    catalogList.add(tmpItem);
                    isContinue = false;
                }
            }
            try {
                download(catalogList,shopInfo);
            } catch (IOException e) {
                logger.error("缓存至本地出现异常："+e.getMessage());
                throw new RuntimeException(e);
            }
        }
    }

    @Override
    protected <T> void download(T param, ShopInfo shop) throws IOException, IllegalArgumentException {
        // 泛型转换
        List<Item> catalogList = null;
        if(param instanceof Collection<?>){
            @SuppressWarnings("unchecked")
            Collection<Item> items = (Collection<Item>) (Collection<?>) param;
            catalogList = new ArrayList<>(items);
        }

        apiRequestLog.setStatus(ApiRequestLog.SYNCING);
        int dataVolumes = apiRequestLog.getDataVolume() == null ? 0 : apiRequestLog.getDataVolume();
        apiRequestLog.setDataVolume(dataVolumes+catalogList.size());
        apiRequestLogService.getBaseMapper().updateById(apiRequestLog);

        int size = catalogList.size();
        List<TmpAmazonCatalogitems> catalogitemsList = new ArrayList<>(size);
        for (Item item : catalogList) {
            logger.info("正在封装"+shop.getId()+"店铺的数据，剩余："+size--);
            TmpAmazonCatalogitems tmp = new TmpAmazonCatalogitems();

            tmp.setSid(shop.getId());
            // marketplaceId
            String marketplaceId = shop.getMarketplaceId();
            tmp.setMarketplaceid(marketplaceId);
            // asin
            tmp.setAsin(item.getAsin());

            ItemRelationships relationships = item.getRelationships();
            if (relationships != null){
                Optional<ItemRelationshipsByMarketplace> exist1 = relationships.stream()
                        .filter(r -> r.getMarketplaceId().equals(marketplaceId)).findFirst();
                if (exist1.isPresent()){
                    ItemRelationshipsByMarketplace itemRelationshipsByMarketplace = exist1.get();
                    Optional<ItemRelationship> exist = itemRelationshipsByMarketplace.getRelationships().stream()
                            .filter(r -> r.getType().equals(ItemRelationship.TypeEnum.VARIATION)).findFirst();
                    if(exist.isPresent()){
                        ItemRelationship itemRelationship = exist.get();
                        // parent_asin
                        String parentAsin = itemRelationship.getParentAsins().stream().collect(Collectors.joining(","));
                        tmp.setParentAsin(parentAsin);
                    }
                }
            }

            // product_type
            ItemProductTypes productTypes = item.getProductTypes();
            if(productTypes != null){
                Optional<ItemProductTypeByMarketplace> exist = productTypes.stream().filter(r -> r.getMarketplaceId().equals(marketplaceId)).findFirst();
                if(exist.isPresent()){
                    ItemProductTypeByMarketplace itemProductTypeByMarketplace = exist.get();
                    String productType = itemProductTypeByMarketplace.getProductType();
                    tmp.setProductType(productType);
                }
            }

            ItemSummaries summaries = item.getSummaries();
            if(null != summaries){
                Optional<ItemSummaryByMarketplace> exist = summaries.stream()
                        .filter(s -> s.getMarketplaceId().equals(marketplaceId))
                        .findFirst();
                if (exist.isPresent()){
                    ItemSummaryByMarketplace itemSummaryByMarketplace = exist.get();
                    // amazon_classify
                    String amazonClassify = itemSummaryByMarketplace.getItemClassification().getValue();
                    tmp.setAmazonClassify(amazonClassify);
                    // brand
                    String brand = itemSummaryByMarketplace.getBrand();
                    tmp.setBrand(brand);
                    // manufacturer
                    String manufacturer = itemSummaryByMarketplace.getManufacturer();
                    tmp.setManufacturer(manufacturer);
                    // product_name
                    String itemName = itemSummaryByMarketplace.getItemName();
                    tmp.setProductName(itemName);
                }
            }

            ItemSalesRanks salesRanks = item.getSalesRanks();
            if(salesRanks != null){
                Optional<ItemSalesRanksByMarketplace> exist = salesRanks.stream()
                        .filter(r -> r.getMarketplaceId().equals(marketplaceId)).findFirst();
                if (exist.isPresent()){
                    ItemSalesRanksByMarketplace itemSalesRanksByMarketplace = exist.get();
                    List<ItemDisplayGroupSalesRank> displayGroupRanks = itemSalesRanksByMarketplace.getDisplayGroupRanks();
                    if(displayGroupRanks != null && displayGroupRanks.size() != 0){
                        // seller_category
                        String sellerCategoru = displayGroupRanks.stream()
                                .map(r -> r.getTitle()).collect(Collectors.joining(","));
                        tmp.setSellerCategory(sellerCategoru);
                        // ranking
                        Integer rank = displayGroupRanks.get(0).getRank();
                        tmp.setRanking(rank);
                    }
                    // small_rank
                    List<ItemClassificationSalesRank> classificationRanks = itemSalesRanksByMarketplace.getClassificationRanks();
                    if (classificationRanks != null && classificationRanks.size() != 0){
                        Integer smallRanking = itemSalesRanksByMarketplace.getClassificationRanks().get(0).getRank();
                        tmp.setSmallRank(smallRanking);
                    }
                }
            }

            ItemIdentifiers identifiers = item.getIdentifiers();
            if(identifiers != null && identifiers.size() != 0){
                List<ItemIdentifier> itemIdentifiers = identifiers.get(0).getIdentifiers();
                if(itemIdentifiers != null && itemIdentifiers.size() != 0){
                    // 可能存在多个
                    // gtin
                    tmp.setGtin(itemIdentifiers.get(0).getIdentifierType().equals("GTIN"));
                    // product_code
                    tmp.setProductCode(itemIdentifiers.get(0).getIdentifier());
                }
            }

            // 获取图片
            ItemImages images = item.getImages();
            if(images != null && images.size() != 0){
                final ItemImagesByMarketplace itemImagesByMarketplace = item.getImages().stream()
                        .filter(i -> i.getMarketplaceId().equals(marketplaceId))
                        .findFirst()
                        .get();
                final ItemImage main = itemImagesByMarketplace.getImages().stream().filter(i -> i.getVariant().getValue().equals("MAIN")).findFirst().get();
                if(null != main){
                    // 验证图片是否需要更新
                    List<ListingFather> exist = listingFather.stream().filter(r ->
                            r.getShop().equals(shop.getId()) && r.getAsin().equals(item.getAsin())).collect(Collectors.toList());
                    for (ListingFather father : exist) {
                        if(father.getImageUrl() == null || !father.getImageUrl().equals(main.getLink())){
                            father.setImageUrl(main.getLink());
                            List<SysFile> image = uploadImage(main.getLink());
                            father.setImg(image);
                            updateImageList.add(father);
                        }
                    }
                }
            }
            catalogitemsList.add(tmp);
        }
        // 记录本次数据同步量
        Integer dataVolume = apiRequestLog.getDataVolume() == null ? 0 : apiRequestLog.getDataVolume();
        apiRequestLog.setDataVolume(dataVolume+catalogitemsList.size());
        tmpAmazonCatalogitemsService.saveBatch(catalogitemsList);
    }

    @Override
    protected void updateOrInsertData() {
        listingFatherService.updateBatchById(updateImageList);

        tmpAmazonCatalogitemsService.getBaseMapper().insertOrUpdate();

        tmpAmazonCatalogitemsService.getBaseMapper().updateFromCatalogItems();

    }
    private List<SysFile> uploadImage(String picUrl) {
        List<SysFile> fileList = new ArrayList<>();
        if (picUrl != null && !picUrl.isEmpty()) {
            MultipartFile multipartFile = null;
            try {
                multipartFile = onlineAddressTransferFile(picUrl);
                if (multipartFile != null) {
                    SysFile file = fileService.upload(multipartFile, null);
                    fileList.add(file);
                }
            } catch (Exception e) {
                logger.error("上传失败：" + picUrl, e);
            }
        }
        return fileList;
    }

    private MultipartFile onlineAddressTransferFile(String strUrl) throws IOException {
        InputStream stream = getInputStreamByUrl(strUrl);
        if (!ObjectUtils.isEmpty(stream)) {
            return new MockMultipartFile("网络图片", FileUtil.getName(strUrl), "image/jpeg", stream);
        } else {
            logger.error("获取网络文件失败 > " + strUrl);
        }
        return null;
    }

    private InputStream getInputStreamByUrl(String strUrl) {
        HttpURLConnection conn = null;
        try {
            if (org.apache.commons.lang3.StringUtils.isNotBlank(strUrl)) {
                URL url = new URL(strUrl);
                conn = (HttpURLConnection) url.openConnection();
                conn.setRequestMethod("GET");
                conn.setConnectTimeout(20 * 1000);

                final ByteArrayOutputStream output = new ByteArrayOutputStream();
                InputStream inputStream = conn.getInputStream();
                IOUtils.copy(inputStream, output);
                return new ByteArrayInputStream(output.toByteArray());
            }
        } catch (FileNotFoundException e) {
            logger.error("FileNotFoundException: " + strUrl);
        } catch (Exception e) {
            logger.error("获取图片时失败，未知异常: " + strUrl, e);
        } finally {
            try {
                if (conn != null) {
                    conn.disconnect();
                }
            } catch (Exception e) {
                logger.error("获取图片时，连接失败: " + strUrl, e);
            }
        }
        return null;
    }

    public void test() throws ApiException {

        // 获取卖家账号信息
        String platform = "Amazon";
        this.getAuthority(platform);

        LambdaQueryWrapper<ShopInfo> shopInfosWrapper = new LambdaQueryWrapper<>();
        shopInfosWrapper.eq(ShopInfo::getPlatform,"Amazon")
                .eq(ShopInfo::getSellerAuthStatus,"SQ01")
                .eq(ShopInfo::getId,1659858464882671618L);
        List<ShopInfo> shopInfoList = shopInfoServiceImpl.list(shopInfosWrapper);
        ShopInfo shopInfo = shopInfoList.get(0);
        CatalogApi catalogApi = amazonUtil.getCatalogApi(entityAuthority, shopInfo);

        List<String> marketplaceIds = new ArrayList<>();
        marketplaceIds.add(shopInfo.getMarketplaceId());
        List<String> includedData = new ArrayList<>();
        //查询参数
        includedData.add("attributes");
        includedData.add("dimensions");
        includedData.add("identifiers");
        includedData.add("images");
        includedData.add("productTypes");
        includedData.add("relationships");
        includedData.add("salesRanks");
        includedData.add("summaries");

        Item items = catalogApi.getCatalogItem("B08TTVCN7D", marketplaceIds, includedData, null);
        TmpAmazonCatalogitems tmp = new TmpAmazonCatalogitems();
        ItemIdentifiers identifiers = items.getIdentifiers();
        if(identifiers != null && identifiers.size() != 0){
            List<ItemIdentifier> itemIdentifiers = identifiers.get(0).getIdentifiers();
            if(itemIdentifiers != null){
                // 可能存在多个
                // gtin
                tmp.setGtin(itemIdentifiers.get(0).getIdentifierType().equals("GTIN"));
                // product_code
                tmp.setProductCode(itemIdentifiers.get(0).getIdentifier());
            }
        }
        tmpAmazonCatalogitemsService.save(tmp);
    }

}
